/******************* Contiene las variables y funciones globales ****************/
/* Obtengo los parametros de la clase parser.cpp y los asigno a las variables globales
 *
 * [0] = representacion
 * [1] = cantidadDePoblacionesEnGpu
 * [2] = cantidadDePoblacionesEnCpu
 * [3] = tamanioPoblacion
 * [4] = cantidadGenesPorIndividuo
 * [5] = metodoDeSeleccion
 * [6] = operadorCruzamiento
 * [7] = operadorMutacion
 * [8] = mecanismoDeReemplazo
 * [9] = probabilidadCruzamiento
 * [10] = probabilidadMutacion
 * [11] = numeroGeneraciones
 * [12] = gradoNoUniformidad
 * [13] = bloquePorPoblacion
 * [14] = porcentajeElitismo
 * [15] = generacionesMigrar
 * [16] = modoDebug
 * [17] = cantidadIndiviuosSeleccionPorRango
 * [18] = criterioDeParada
 * [19] = metodoInicializacion
 */

#ifndef GLOBAL_CU
#define GLOBAL_CU

#include "global.cuh"

/******************* Implementación de Funciones del Device *****************/

__global__ void asignarParametrosDevice(float * parametros){
	cantidadPoblacionesGPUDevice = (int) parametros[1];
	cantidadPoblacionesCPUDevice = (int) parametros[2];
	cantCromosomasPoblacionDevice = (int) parametros[3];
	cantGenesEnCromosomaDevice = (int) parametros[4];
	totalGenesEnPoblacionDevice = cantCromosomasPoblacionDevice * cantGenesEnCromosomaDevice;
	tipoSeleccionDevice = (int) parametros[5];
	tipoCruzamientoDevice = (int) parametros[6];
	tipoMutacionDevice = (int) parametros[7];
	tipoReemplazoDevice = (int) parametros[8];
	probabilidadCruzamientoDevice = parametros[9];
	probabilidadMutacionDevice = parametros[10];
	numeroGeneracionesDevice = (int) parametros[11];
	gradoNoUniformidadDevice = parametros[12];
	porcentajeElitismoDevice = parametros[14];
	generacionesMigrarDevice = (int) parametros[15];
	cantidadIndividuosSeleccionPorRangoDevice = (int) parametros[17];
}

__device__ int estaPresente(int valor, int* nuevaPoblacion, int desde, int hasta){
	for (int i = desde; i< hasta; i++) {
		if (nuevaPoblacion[i] == valor)
			return 1;
	}
	return 0;
}

__device__ int posicionPrimerLibre(int* poblacionActual, int posicionNuevoCromosoma){
	for(int i=0; i<cantGenesEnCromosomaDevice; i++){
		if(poblacionActual[posicionNuevoCromosoma+i]==-1)
			return i;
	}
	return -1;
}

__device__ int dondeEsta(int* poblacionActual, int valor, int posicionNuevoCromosoma){

	for(int i=0; i<cantGenesEnCromosomaDevice; i++){
		if(poblacionActual[posicionNuevoCromosoma+i]==valor)
			return i;
	}
	return 0;
}

//en lugar de guardar el valor del fitness en el data, tengo que guardar el indice correspondiente al elemento del data anterior para despues hacer el mapeo
__global__ void ordenarDescendente(float *fitnesAOrdenar, int *indicesFitnessOrdenado) {
//	cuPrintf("\nOrdenar descendente\n");

	int left = blockIdx.y * cantCromosomasPoblacionDevice;
	int right = left + cantCromosomasPoblacionDevice;
	for(int i = left ; i < right ; i++) {
		indicesFitnessOrdenado[i] = i % cantCromosomasPoblacionDevice;
	}
	int aux;
	for(int i = left ; i < right ; i++) {
		float max_val = fitnesAOrdenar[i];
		int max_idx = i;
		// Find the bigest value in the range [left, right].
		for(int j = i+1 ; j < right ; j++) {
			float val_j = fitnesAOrdenar[j];
			if( val_j > max_val ) {
				max_idx = j;
				max_val = val_j;
			}
		}
		// Swap the values.
		if(i != max_idx) {
			fitnesAOrdenar[max_idx] = fitnesAOrdenar[i];
			fitnesAOrdenar[i] = max_val;

			aux = indicesFitnessOrdenado[max_idx];
			indicesFitnessOrdenado[max_idx] = indicesFitnessOrdenado[i];
			indicesFitnessOrdenado[i] = aux;
		}
	}
}


/******************* Implementacion de Funciones del host *****************/

int estaPresenteCPU(int valor, int* nuevaPoblacion, int desde, int hasta){
	for (int i = desde; i< hasta; i++) {
		if (nuevaPoblacion[i] == valor)
			return 1;
	}
	return 0;
}

int posicionPrimerLibreCPU(int* poblacionActual, int posicionNuevoCromosoma){
	for(int i=0; i<cantGenesEnCromosoma; i++){
		if(poblacionActual[posicionNuevoCromosoma+i]==-1)
			return i;
	}
	return -1;
}

int dondeEstaCPU(int* poblacionActual, int valor, int posicionNuevoCromosoma){

	for(int i=0; i<cantGenesEnCromosoma; i++){
		if(poblacionActual[posicionNuevoCromosoma+i]==valor)
			return i;
	}
	return 0;
}

//__host__ puede ponerse o no
/*
 * Idem a asignarParametrosDevice()
 * Obtengo los parametros de la clase parser.cpp y los asigno a las variables globales
 *
 * [0] = representacion
 * [1] = cantidadDePoblacionesEnGpu
 * [2] = cantidadDePoblacionesEnCpu
 * [3] = tamanioPoblacion
 * [4] = cantidadGenesPorIndividuo
 * [5] = metodoDeSeleccion
 * [6] = operadorCruzamiento
 * [7] = operadorMutacion
 * [8] = mecanismoDeReemplazo
 * [9] = probabilidadCruzamiento
 * [10] = probabilidadMutacion
 * [11] = numeroGeneraciones
 * [12] = gradoNoUniformidad
 * [13] = bloquePorPoblacion
 * [14] = porcentajeElitismo
 * [15] = generacionesMigrar
 * [16] = modoDebug
 * [17] = cantidadIndiviuosSeleccionPorRango
 * [18] = criterioDeParada
 * [19] = metodoInicializacion
 */
void asignarParametros(float * parametros){
	tipoRepresentacion = (int) parametros[0];
	cantidadPoblacionesGPU = (int) parametros[1];
	cantidadPoblacionesCPU = (int) parametros[2];
	cantCromosomasPoblacion = (int) parametros[3];
	cantGenesEnCromosoma = (int) parametros[4];
	totalGenesEnPoblacion = cantCromosomasPoblacion * cantGenesEnCromosoma;
	tipoSeleccion = (int) parametros[5];
	tipoCruzamiento= (int) parametros[6];
	tipoMutacion = (int) parametros[7];
	tipoReemplazo = (int) parametros[8];
	probabilidadCruzamiento = parametros[9];
	probabilidadMutacion = parametros[10];
	numeroGeneraciones = (int) parametros[11];
	gradoNoUniformidad = parametros[12];
	bloquePorPoblacion = (int) parametros[13];
	porcentajeElitismo = parametros[14];
	generacionesMigrar = (int) parametros[15];
	modoDebug = (int) parametros[16];
	cantidadIndividuosSeleccionPorRango = (int) parametros[17];
}

//en lugar de guardar el valor del fitness en el data, tengo que guardar el indice correspondiente al elemento del data anterior para despues hacer el mapeo
void ordenarDescendenteCPU(float *fitnesAOrdenar, int *indicesFitnessOrdenado, int nroPoblacion) {
	int left = nroPoblacion * cantCromosomasPoblacion;
	int right = left + cantCromosomasPoblacion;
	for(int i = left ; i < right ; i++) {
		indicesFitnessOrdenado[i] = i % cantCromosomasPoblacion;
	}
	int aux;
	for(int i = left ; i < right ; i++) {
		float max_val = fitnesAOrdenar[i];
		int max_idx = i;
		// Find the bigest value in the range [left, right].
		for(int j = i+1 ; j < right ; j++) {
			float val_j = fitnesAOrdenar[j];
			if( val_j > max_val ) {
				max_idx = j;
				max_val = val_j;
			}
		}
		// Swap the values.
		if(i != max_idx) {
			fitnesAOrdenar[max_idx] = fitnesAOrdenar[i];
			fitnesAOrdenar[i] = max_val;
			aux = indicesFitnessOrdenado[max_idx];
			indicesFitnessOrdenado[max_idx] = indicesFitnessOrdenado[i];
			indicesFitnessOrdenado[i] = aux;
		}
	}
}

#endif
